'''
Created on Jul 21, 2011

@author: bstar
'''
from zope.interface import implements
from lxml import etree
from twisted.plugin import IPlugin
import os
import logging
import traceback

from dopplershift.collector.renderers.default import IDSCollectorRenderer
from dopplershift.core.plugins.interfaces import IDSPlugin
from dopplershift.collector.renderers.default import DefaultRenderer
from dopplershift.core.utils.xmlserializer import DSXMLSerializer
from dopplershift.core.containers.mediator import getMediator

logger = logging.getLogger(__name__)


class XSLTRenderer(DefaultRenderer):

    name = "xml.xslt"
    default_content_type = 'text/xml'
    implements(IPlugin, IDSPlugin, IDSCollectorRenderer)


    def configure(self, config):
        self._access_control = etree.XSLTAccessControl(read_network=False, read_file=True)
        DefaultRenderer.configure(self, config)


    def getTemplate(self, template_name):
        if template_name in self._templates:
            return self._templates[template_name]
        f = self.loadFile(template_name, as_handler=True)
        if f is not None:
            try:
                self._templates[template_name] = etree.XSLT(
                                                        etree.parse(
                                                                  f
                                                                  ), access_control=self._access_control
                                                        )
                return self._templates[template_name]
            except:
                logger.exception("{getTemplate}, except error while opening <%s> file", template_name)
                return False
        else:
            logger.warning("{getTemplate}, file not found: %s", template_name)


    def rendering(self, request, data, template_name, content_type):
        result = {}
        
        if template_name is None:
            result = etree.tostring(data)
        else:
            tmpl = self.getTemplate(template_name)
            
            try:
                result = str(tmpl(data))
            except:
                return self.error(request, 500)
        request.setHeader('Content-Type', content_type)
        request.write(result)
        try:
            request.finish()
        except:
            logger.debug("Except redirect, because user close connection")


    def prepare(self, data, calls_idents, matched_params, auth_user, as_string=True, request=None):
        material = etree.Element('material')
        session = {}
        redirect = None
        result = {
                  'material': material,
                  'session': session
                  }
        for el in calls_idents:
            err_excp = el.getExcepting()
            node_id = el.getNodeName()
            if node_id not in data and err_excp == '500':
                return self.renderInternalServerError() 
            r = self.prepare_xml_data(data[node_id], as_string=True)
            if r is not None and r != False:
                self._processContent(r, material, node_id)
            session.update(self.session(r))
            if redirect is None:
                redirect = self.redirect(r)
        if not redirect is None:
            result['redirect'] = redirect
        if matched_params != None:
            material.append(DSXMLSerializer("matched_params", matched_params)(get_as_etree=True))
        if auth_user != None and auth_user != False:
            material.append(DSXMLSerializer("auth_user", auth_user)(get_as_etree=True))
        if request is not None:
            material.append(DSXMLSerializer("request", request.args)(get_as_etree=True))
        return result


    def _processContent(self, data, material, node_id='node'):
        content_cnt = 0
        for content in data.xpath('''content'''):
            content_cnt += 1
            node = etree.SubElement(material, node_id)
            node.append(content)
        return True


    def session(self, data):
        return {}


    def redirect(self, data):
        if isinstance(data, bool):
            return
        for el in data.xpath('redirect/@url'):
            return el
        return False


    def prepare_xml_data(self, data, as_string=True):
        try:
            return etree.fromstring(data)
        except:
            return None


    def error_render(self, request, code, as_string=False):
        request.setResponseCode(code)
        tmpl = self._prerendered_errors.get(str(code))
        
        r = str(tmpl(etree.Element('error', {"code": str(code)})))
        if as_string==True:
            return r
        request.write(r)
        request.finish()
        return
            